#include <iostream>
using namespace std;

//多态的基本概念
//多态可分为静态多态：函数重载和运算符重载 ， 属于静态多态 ，复用函数名
//        动态多态：派生类和虚函数 实现运行多态

//静态多态和动态多态的区别：
// 静态多态 ： 函数地址早绑定 —— 编译阶段 确定函数地址
// 动态多态 ： 函数地址晚绑定 —— 运行阶段 确定函数地址

//动态多态满足条件  ： 1.有继承关系
//                 2.父类指针或引用指向子类对象

class Animal {
public:
    virtual void speak() {
        cout << "动物在叫" << endl;
    }
};

class Cat : public Animal {
public:
    void speak() {
        cout << "小猫在叫" << endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        cout << "小狗在叫" << endl;
    }
};

//Animal & a 在未加virtual时它属于静态多态，调用Speak函数时，会调用Animal的speak函数 ，早绑定，让使之即使传入的是猫类或狗类，
// 调用时显示自己类中的信息 ，便要是指改为晚绑定即可 ，为动态多态 ， 运行时再确定调用的函数 在父类该函数前加virtual
void Speak(Animal & a) {
    a.speak();
}

void test01() {
    Cat c;
    Speak(c);
    Dog d;
    Speak(d);
}

int main() {
    test01();
    cout << sizeof(Animal) << endl;
    //当Animal类中的成员函数不是虚函数时 ，他不属于与类上 ， 故为空对象 字节为1
    //          但是时虚函数时，会为Animal类创建一个虚函数表指针 ， 他的大小取决于与系统位数 32位为4字节 64位为8字节
    return 0;
}


//动态动态的底层原理：
// vfptr v:virtual f:function ptr:pointer  虚函数（表）指针
// vftable 虚函数表 ， 记录虚函数的地址

//当子类重写父类中的虚函数时，子类的虚函数表内部指针会替换成子类函数地址 ， 父类指针调用子类函数时，会调用子类函数